package pers.chao.logger.core.aspect;

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import pers.chao.tool.aspect.AopUtil;
import pers.chao.tool.date.EasyDateFormat;
import pers.chao.tool.encrypt.EasyEncrypt;
import pers.chao.tool.math.RandomUtil;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * Description: 方法相关日志内容获取
 *
 * @author W.Chao
 * @date 2020/11/19 23:17
 **/
public class MethodInterceptorHolder {
	private String id;
	private Method method;
	private Object target;
	private Map<String, Object> args;

	private static final ParameterNameDiscoverer nameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
	private static final String FIXED_IDENTIFIER = "METHOD_LOG_";

	public MethodInterceptorHolder(String id, Method method, Object target, Map<String, Object> args) {
		this.id = id;
		this.method = method;
		this.target = target;
		this.args = args;
	}

	public String getId() {
		return id;
	}

	public Method getMethod() {
		return method;
	}

	public Object getTarget() {
		return target;
	}

	public Map<String, Object> getArgs() {
		return args;
	}

	public static MethodInterceptorHolder create(MethodInvocation invocation) {
		String[] argNames = nameDiscoverer.getParameterNames(invocation.getMethod());
		Object[] args = invocation.getArguments();
		Map<String, Object> argMap = null;

		// 构建唯一id的种子
		StringBuilder seed = new StringBuilder(FIXED_IDENTIFIER + RandomUtil.randomChar(8) +
				invocation.getMethod().getDeclaringClass().getName() + invocation.getMethod().getName() +
				EasyDateFormat.getNowyyyyMMddHHmmssSSS());
		if (argNames != null) {
			argMap = AopUtil.getMethodArgsMap(argNames, args);
			argMap.forEach((k, v) -> seed.append(k).append(v).append("+"));
		} else {
			seed.append(RandomUtil.random128Char());
		}
		String id = EasyEncrypt.md5(seed.toString());

		return new MethodInterceptorHolder(id, invocation.getMethod(),
				invocation.getThis(), argMap);
	}

	// ******************************
	// 提供相应接口获取类、方法上的注解
	// ******************************

	public <T extends Annotation> T findMethodAnnotation(Class<T> annClass) {
		return AopUtil.findMethodAnnotation(annClass, method, annClass);
	}

	public <T extends Annotation> T findClassAnnotation(Class<T> annClass) {
		return AopUtil.findAnnotation(target.getClass(), annClass);
	}

	public <T extends Annotation> T findAnnotation(Class<T> annClass) {
		return AopUtil.findAnnotation(target.getClass(), method, annClass);
	}
}
